package helper.scxml.scxml2.t6_zone

import helper.base.ConstraintHelper.CompareOp.Companion.eOp
import helper.base.ConstraintHelper.CompareOp.Companion.gOp
import helper.base.ConstraintHelper.CompareOp.Companion.geOp
import helper.base.ConstraintHelper.CompareOp.Companion.lOp
import helper.base.ConstraintHelper.CompareOp.Companion.leOp
import helper.base.ConstraintHelper.W1N1N2ConstraintHelper.getXConstraint
import helper.base.ConstraintHelper.W1N1N2ConstraintHelper.getXYConstraint
import helper.base.ConstraintHelper.W1N1N2ConstraintHelper.getYConstraint
import helper.scxml.scxml2.t6_zone.ConfigHelperTest.ZoneGraphObjHelper.getZoneGraphObj1
import helper.scxml.scxml2.t6_zone.ConfigHelperTest.ZoneGraphObjHelper.getZoneGraphObj2
import helper.scxml.scxml2.t6_zone.ConfigHelperTest.ZoneGraphObjHelper.getZoneGraphObj3
import helper.scxml.scxml2.t6_zone.ConfigHelperTest.ZoneGraphObjHelper.getZoneGraphObj4
import helper.scxml.scxml2.zone.t1.ZoneStateHelper.ZoneGraph
import helper.scxml.scxml2.zone.t1.ZoneStateHelper.ZonePath
import helper.scxml.scxml2.zone.t1.ZoneStateHelper.ZoneState
import helper.scxml.scxml2.zone.t1.ZoneStateHelper.ZoneState.Companion.getL1C1ZoneState
import helper.scxml.scxml2.zone.t1.ZoneStateHelper.ZoneState.Companion.getL1C2ZoneState
import helper.scxml.scxml2.zone.t1.ZoneStateHelper.ZoneTransition.Companion.getAutoEventZoneTransition
import helper.scxml.scxml2.zone.t1.ZoneStateHelper.touchPrintlnType2
import org.junit.Test

internal class ConfigHelperTest {
    private object ZoneGraphObjHelper {
        fun getZSList1(): ArrayList<ZoneState> {
            val zone0 = getL1C1ZoneState(
                "l0",
                getXYConstraint(eOp, 0.0),
            )
            val zone1 = getL1C2ZoneState(
                "l1",
                getXConstraint(geOp, 0.0, lOp, 1.0),
                getXYConstraint(leOp, 0.0),
            )
            val zone2 = getL1C2ZoneState(
                "l2",
                getXConstraint(geOp, 0.0, lOp, 1.0),
                getYConstraint(geOp, 0.0),
            )
            val zone3 = getL1C2ZoneState(
                "l3",
                getXConstraint(geOp, 0.0),
                getYConstraint(geOp, 0.0),
            )
            val zone4 = getL1C2ZoneState(
                "l0",
                getXConstraint(gOp, 2.0),
                getYConstraint(gOp, 2.0),
            )
            val zsList = arrayListOf(
                zone0,
                zone1,
                zone2,
                zone3,
                zone4,
            )
            zsList.withIndex().map { (a1, a2) ->
                a2.name = "z${a1}"
            }
            return zsList
        }

        fun getZoneGraphObj1(): ZoneGraph {
            val zsList = getZSList1()
            val (zone0, zone1, zone2, zone3, zone4) = zsList
            val ts = arrayListOf(
                getAutoEventZoneTransition(zone0, zone1),
                getAutoEventZoneTransition(zone1, zone2),
                getAutoEventZoneTransition(zone2, zone3),
                getAutoEventZoneTransition(zone3, zone3),
                getAutoEventZoneTransition(zone3, zone4),
                getAutoEventZoneTransition(zone4, zone1),
            )
            return ZoneGraph(
                zone0,
                ts,
            )
        }

        fun getZoneGraphObj2(): ZoneGraph {
            val zsList = getZSList1()
            val (zone0, zone1, zone2, zone3, zone4) = zsList
            val ts = arrayListOf(
                getAutoEventZoneTransition(zone0, zone1),
                getAutoEventZoneTransition(zone1, zone2),
                getAutoEventZoneTransition(zone1, zone3),
                getAutoEventZoneTransition(zone2, zone3),
                getAutoEventZoneTransition(zone3, zone3),
                getAutoEventZoneTransition(zone3, zone4),
            )
            return ZoneGraph(
                zone0,
                ts,
            )
        }

        fun getZoneGraphObj3(): ZoneGraph {
            val zsList = getZSList1()
            val (zone0, zone1, zone2, zone3, zone4) = zsList
            zone3.reward = 60.0
            zone4.reward = 50.0
            val ts = arrayListOf(
                getAutoEventZoneTransition(zone0, zone1),
                getAutoEventZoneTransition(zone1, zone2),
                getAutoEventZoneTransition(zone1, zone3),
                getAutoEventZoneTransition(zone1, zone4),
                getAutoEventZoneTransition(zone2, zone3),
            )
            return ZoneGraph(
                zone0,
                ts,
                finalStates = linkedSetOf(
                    zone3,
                    zone4,
                ),
            )
        }

        fun getZoneGraphObj4(): ZoneGraph {
            val zsList = getZSList1()
            val (zone0, zone1, zone2, zone3, zone4) = zsList
            zone3.reward = 60.0
            zone4.reward = 50.0
            val z1z3 = getAutoEventZoneTransition(zone1, zone3)
            val z1z4 = getAutoEventZoneTransition(zone1, zone4)
            val ts = arrayListOf(
                getAutoEventZoneTransition(zone0, zone1),
                getAutoEventZoneTransition(zone1, zone2),
                z1z3,
                z1z4,
                getAutoEventZoneTransition(zone2, zone3),
            )
            val zoneGraph = ZoneGraph(
                zone0,
                ts,
                finalStates = linkedSetOf(
                    zone3,
                    zone4,
                ),
            )
            zoneGraph.stateEventPLHM.let {
                //概率生效
                it[zone1]!![z1z3.eventChoice] = 2.0
                it[zone1]!![z1z4.eventChoice] = 2.0
            }
            return zoneGraph
        }
    }

    @Test
    fun t1t1() {
        val zoneGraph = getZoneGraphObj1()
        val rs = zoneGraph.stateEventTLHM.touchPrintlnType2().trim()
        println(rs)
        assert(
            rs == """
            ----------------------------------------
            [z0,(l0),(x-y=0.0)]
            [z0z1]
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            ----------------------------------------
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            [z1z2]
            [z2,(l2),(0.0<=x<1.0 and y>=0.0)]
            ----------------------------------------
            [z2,(l2),(0.0<=x<1.0 and y>=0.0)]
            [z2z3]
            [z3,(l3),(x>=0.0 and y>=0.0)]
            ----------------------------------------
            [z3,(l3),(x>=0.0 and y>=0.0)]
            [z3z3]
            [z3,(l3),(x>=0.0 and y>=0.0)]
            ----------------------------------------
            [z3,(l3),(x>=0.0 and y>=0.0)]
            [z3z4]
            [z4,(l0),(x>2.0 and y>2.0)]
            ----------------------------------------
            [z4,(l0),(x>2.0 and y>2.0)]
            [z4z1]
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
        """.trimIndent()
        )
    }

    @Test
    fun t1t2() {
        val zoneGraph = getZoneGraphObj1()
        val rs = zoneGraph.dfsTouchType11().trim()
        println(rs)
        assert(
            rs == """
[z0,(l0),(x-y=0.0)]
	[z0z1][z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
		[z1z2][z2,(l2),(0.0<=x<1.0 and y>=0.0)]
			[z2z3][z3,(l3),(x>=0.0 and y>=0.0)]
				[z3z3][z3,(l3),(x>=0.0 and y>=0.0)]
					[z3z4][z4,(l0),(x>2.0 and y>2.0)]
						[z4z1][z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
        """.trimIndent()
        )
    }

    @Test
    fun t2t1() {
        val zoneGraph = getZoneGraphObj2()
        val rs = zoneGraph.dfsTouchType11().trim()
        println(rs)
        assert(
            rs == """
[z0,(l0),(x-y=0.0)]
	[z0z1][z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
		[z1z2][z2,(l2),(0.0<=x<1.0 and y>=0.0)]
			[z2z3][z3,(l3),(x>=0.0 and y>=0.0)]
				[z3z3][z3,(l3),(x>=0.0 and y>=0.0)]
					[z3z4][z4,(l0),(x>2.0 and y>2.0)]
		[z1z3][z3,(l3),(x>=0.0 and y>=0.0)]
        """.trimIndent()
        )
    }

    @Test
    fun t3() {
        val zoneGraph = getZoneGraphObj3()
        val rs1 = zoneGraph.stateEventTLHM.touchPrintlnType2()
        val rs2 = zoneGraph.stateEventPLHM.touchPrintlnType2()
        val pathList: ArrayList<ZonePath> = ArrayList()
        zoneGraph.dfsTouchType2(
            pathList = pathList,
        )
        val sb3 = StringBuilder()
        pathList.map {
            sb3.append("$it\n")
        }
        val rs3 = sb3.toString().trim()
        println(rs1)
        println(rs2)
        println(rs3)
        assert(
            rs1.trim() == """
            ----------------------------------------
            [z0,(l0),(x-y=0.0)]
            [z0z1]
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            ----------------------------------------
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            [z1z2]
            [z2,(l2),(0.0<=x<1.0 and y>=0.0)]
            ----------------------------------------
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            [z1z3]
            [z3,(l3),(x>=0.0 and y>=0.0)]
            ----------------------------------------
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            [z1z4]
            [z4,(l0),(x>2.0 and y>2.0)]
            ----------------------------------------
            [z2,(l2),(0.0<=x<1.0 and y>=0.0)]
            [z2z3]
            [z3,(l3),(x>=0.0 and y>=0.0)]
        """.trimIndent()
        )

        assert(
            rs2.trim() == """
            [z0][z0z1][1.0]
            [z1][z1z2][1.0]
            [z1][z1z3][1.0]
            [z1][z1z4][1.0]
            [z2][z2z3][1.0]
        """.trimIndent()
        )
        assert(
            rs3.trim() == """
            ZonePath((z0,z0z1,z1),(z1,z1z2,z2),(z2,z2z3,z3),pReward=20.0)
            ZonePath((z0,z0z1,z1),(z1,z1z3,z3),pReward=20.0)
            ZonePath((z0,z0z1,z1),(z1,z1z4,z4),pReward=16.666666666666664)
        """.trimIndent()
        )
    }

    @Test
    fun t4() {
        val zoneGraph = getZoneGraphObj4()
        val rs1 = zoneGraph.stateEventTLHM.touchPrintlnType2()
        val rs2 = zoneGraph.stateEventPLHM.touchPrintlnType2()
        val pathList: ArrayList<ZonePath> = ArrayList()
        zoneGraph.dfsTouchType2(
            pathList = pathList,
        )
        val sb3 = StringBuilder()
        pathList.map {
            sb3.append("$it\n")
        }
        val rs3 = sb3.toString()
        println(rs1)
        println(rs2)
        println(rs3)
        assert(
            rs1.trim() == """
            ----------------------------------------
            [z0,(l0),(x-y=0.0)]
            [z0z1]
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            ----------------------------------------
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            [z1z2]
            [z2,(l2),(0.0<=x<1.0 and y>=0.0)]
            ----------------------------------------
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            [z1z3]
            [z3,(l3),(x>=0.0 and y>=0.0)]
            ----------------------------------------
            [z1,(l1),(0.0<=x<1.0 and x-y<=0.0)]
            [z1z4]
            [z4,(l0),(x>2.0 and y>2.0)]
            ----------------------------------------
            [z2,(l2),(0.0<=x<1.0 and y>=0.0)]
            [z2z3]
            [z3,(l3),(x>=0.0 and y>=0.0)]
        """.trimIndent()
        )
        assert(
            rs2.trim() == """
            [z0][z0z1][1.0]
            [z1][z1z2][1.0]
            [z1][z1z3][2.0]
            [z1][z1z4][2.0]
            [z2][z2z3][1.0]
        """.trimIndent()
        )
        assert(
            rs3.trim() == """
            ZonePath((z0,z0z1,z1),(z1,z1z2,z2),(z2,z2z3,z3),pReward=12.0)
            ZonePath((z0,z0z1,z1),(z1,z1z3,z3),pReward=24.0)
            ZonePath((z0,z0z1,z1),(z1,z1z4,z4),pReward=20.0)
        """.trimIndent()
        )
    }

    @Test
    fun t5() {
        val zoneGraph = getZoneGraphObj3()
        val sb1 = StringBuilder()
        zoneGraph.stateLHS.map {
            sb1.append("${it.toString2()}\n")
            sb1.append("${zoneGraph.stateLHS.indexOf(it)}\n")
        }
        val rs1 = sb1.toString()
        println(rs1)
        assert(
            rs1.trim() == """
            z0,(l0),(x-y=0.0)
            0
            z1,(l1),(0.0<=x<1.0 and x-y<=0.0)
            1
            z2,(l2),(0.0<=x<1.0 and y>=0.0)
            2
            z3,(l3),(x>=0.0 and y>=0.0)
            3
            z4,(l0),(x>2.0 and y>2.0)
            4
        """.trimIndent()
        )
    }
}